package com.roarkry.styloid;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

/**
 * @author Danny Remington - MacroSolve
 * 
 *         Helper class for sqlite database.
 *         
 *         http://stackoverflow.com/questions/513084/how-to-ship-an-android-application-with-a-database
 */
public class DatabaseHelper extends SQLiteOpenHelper {

    private static String DB_DIR = "/data/data/com.roarkry.styloid/databases/";
    private static String DB_NAME = "styloid";
    private static String DB_PATH = DB_DIR + DB_NAME;
    
    private static final String TAG = "DatabaseHelper";
    private static final int DATABASE_VERSION = 10;
    private final Context myContext;

    private boolean createDatabase = false;
    private boolean upgradeDatabase = false;

    /**
     * Constructor Takes and keeps a reference of the passed context in order to
     * access to the application assets and resources.
     * 
     * @param context
     */
    public DatabaseHelper(Context context) {    	
    	super(context, DB_NAME, null, DATABASE_VERSION);
    	Log.w(TAG, "Constructor");
        myContext = context;
        // Get the path of the database that is based on the context.
        DB_PATH = myContext.getDatabasePath(DB_NAME).getAbsolutePath();
    }

    /**
     * Upgrade the database in internal storage if it exists but is not current. 
     * Create a new empty database in internal storage if it does not exist.
     */
    public void initializeDataBase() {
    	Log.w(TAG, "initialize Database");
    	this.getWritableDatabase();

        if (createDatabase) {
            try {
                copyDataBase();
            } catch (IOException e) {
                throw new Error("Error copying database");
            }
        } else if (upgradeDatabase) {
            try {
                copyDataBase();
                SQLiteDatabase.openDatabase(DB_PATH,null, SQLiteDatabase.OPEN_READWRITE);
            } catch (IOException e) {
                throw new Error("Error copying database");
            }
        }

    }

    /**
     * Copies your database from your local assets-folder to the just created
     * empty database in the system folder, from where it can be accessed and
     * handled. This is done by transfering bytestream.
     * */
    private void copyDataBase() throws IOException {
    	Log.w(TAG, "Copying Database");
        close();

        InputStream myInput = myContext.getAssets().open(DB_NAME);

        OutputStream myOutput = new FileOutputStream(DB_PATH);

        copyFile(myInput, myOutput);

        getWritableDatabase().close();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        createDatabase = true;
        Log.w(TAG, "onCreate");
    }

    /**
     * Called only if version number was changed and the database has already
     * been created. Copying a database from the application package assets to
     * the internal data system inside this method will result in a corrupted
     * database in the internal data system.
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        upgradeDatabase = true;
        Log.w(TAG, "onUpgrade");
    }

    /**
     * Called everytime the database is opened by getReadableDatabase or
     * getWritableDatabase. This is called after onCreate or onUpgrade is
     * called.
     */
    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
        Log.w(TAG, "onOpen");
    }
    
    /**
     * Copy over a database by bytes
     * 
     * @param fromFile
     *            - InputStream for the file to copy from.
     * @param toFile
     *            - InputStream for the file to copy to.
     */
    public static void copyFile(InputStream fromFile, OutputStream toFile) throws IOException {
    	Log.w(TAG, "copyFile");
    	
    	// transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;

        try {
            while ((length = fromFile.read(buffer)) > 0) {
                toFile.write(buffer, 0, length);
            }
        }
        // Close the streams
        finally {
            try {
                if (toFile != null) {
                    try {
                        toFile.flush();
                    } finally {
                        toFile.close();
                    }
            }
            } finally {
                if (fromFile != null) {
                    fromFile.close();
                }
            }
        }
    }
}
